#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<pthread.h>
#include"../include/seminjector.h"
#include"../include/marshallADT.h"
#include"../include/cityDefs.h"

//para el manejo de señales
static int exitFlag = 0;
static void
exitSigInt(int sign) {
	exitFlag = 1;
}

typedef struct {
	semafT sem;
	marshallADT mar;
}semaphoreT;

void * createSemaphore(void * sem);
int cargaSem(semaphoreT * sem, int i, FILE * fsem);

pthread_mutex_t mutexSem;

/*
 * Encargado de habilitar los semaforos.
 */
void
semInjector(void){

	FILE * sems;
	semaphoreT aux[CANT_SEM];
	int cantsems=0, i, rc;
	pthread_t threads[CANT_SEM];
	marshallADT mar;

	pthread_mutex_init(&mutexSem, NULL);
	//seminjector inicializa la comunicacion con city
	if((mar = getMarsh(SEM_ID, CITY_ID)) == NULL)
		kill(0, SIGUSR1);

	//handler de la señal ctrl+c para cerrar bien el programa
	static struct sigaction act;
	act.sa_handler = exitSigInt;
	sigfillset(&(act.sa_mask));
	sigaction(SIGUSR1, &act, NULL);

	if((sems=fopen("archivos/semaforos", "r"))!=NULL) {
		//lee la cantidad de semaforos
		if(fscanf(sems, "Cantidad de Semaforos:%d\n", &cantsems)==1) {
			for(i=0; i<cantsems; i++){
				//cargo la data de cada semaforo
				if(cargaSem(aux, i, sems)) {
					//todos los semaforos utilizan el mismo medio habilitado previamente
					aux[i].mar=mar;
					//creo el thread que ejecuta un semaforo
					rc = pthread_create(&threads[i], NULL, createSemaphore, (void *)(&aux[i]));
					if (rc){
						printf("ERROR; return code from pthread_create() is %d\n", rc);
						exit(-1);
					}
				} else {
					fclose(sems);
					fprintf(stderr, "ERROR; archivo de semaforos\n");
					exit(1);
				}
			}
		}
		fclose(sems);
	}

	//espero a que me den una señal para salir, si no me la mandaron antes
	if (!exitFlag)
		pause();

	closeMarsh(mar); //cierro el unico marshall abierto para semaforos
	pthread_mutex_destroy(&mutexSem);
	exit(1);
}

/*
 * Carga el semaforo.
 * Retorna 0, en caso de error, 1 en caso contrario.
 */
int
cargaSem(semaphoreT * sem, int index, FILE * fsem) {
	char aux;
	int j,x,y;

	if(fscanf(fsem, "\nx:%d\n", &x)==1 && fscanf(fsem, "y:%d\n", &y)==1) {
		sem[index].sem.pos.x=x;
		sem[index].sem.pos.y=y;
		if((sem[index].sem.pos.x%(BLOCKWIDTH+1))==0 && (sem[index].sem.pos.y%(BLOCKHEIGHT+1))==0) {
			sem[index].sem.pos.x++; //sumo uno porque el mapa tiene un "borde" FORBIDDEN
			sem[index].sem.pos.y++;	//sumo uno porque el mapa tiene un "borde" FORBIDDEN
			for(j=0; j<index; ++j)
				if(sem[index].sem.pos.x==sem[j].sem.pos.x && sem[index].sem.pos.y==sem[j].sem.pos.y)
					return 0;
			if(fscanf(fsem, "intervalo:%d\n", &sem[index].sem.intervalo)==1)
				if(fscanf(fsem, "luz:%c\n", &aux)==1)
					if(aux=='1' || aux=='0') {
						if(aux=='1')
							sem[index].sem.status=TRAFFIC_LIGHT_HOR;
						else
							sem[index].sem.status=TRAFFIC_LIGHT_VER;
						return 1;
					}
		}
	}

	return 0;
}

/*
 * Controlador del semaforo.
 */
void * createSemaphore(void * sem) {
	int aux;

	while(1) {
		pthread_mutex_lock(&mutexSem);
		aux=sendData(((semaphoreT *)sem)->mar, &(((semaphoreT *)sem)->sem), TRAFFIC_LIGHT);
		pthread_mutex_unlock(&mutexSem);
		if(aux==4)
			//cambia la luz
			if(((semaphoreT *)sem)->sem.status==TRAFFIC_LIGHT_HOR)
				((semaphoreT *)sem)->sem.status=TRAFFIC_LIGHT_VER;
			else
				((semaphoreT *)sem)->sem.status=TRAFFIC_LIGHT_HOR;
		else{
			fprintf(stderr, "Error en el semaforo\n");//ERROR de escritura
			exit(1);
		}
		//tarda en cambiar el intervalo inicializado por archivo
		sleep(((semaphoreT *)sem)->sem.intervalo);
	}

	pthread_exit(NULL);

}
